home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 11
/
CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso
/
cucd
/
programming
/
oberonv4
/
source
/
system
/
class.mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1995-12-26
|
9KB
|
267 lines
Syntax10.Scn.Fnt
Syntax10i.Scn.Fnt
Syntax10b.Scn.Fnt
MODULE Class; (** HM 16-May-91 **)
(*---------------------------------------------------------------------
Extracts class interfaces from a source module (record types with type-bound procedures)
Class.Show *
shows the interface of all record types in the marked source text.
Class.Show modulename.typename
shows the interface of the specified type.
Class.Show ^
shows the interface of the specified type. The selection may be
- a type name directly in the source text.
- a combination modulename.typename in any text.
----------------------------------------------------------------------*)
IMPORT
Oberon, Viewers, Texts, TextFrames, MenuViewers;
CONST
StdMenu = "System.Close System.Copy System.Grow Edit.Search Edit.Store";
TAB = 9X; CR = 0DX;
eot = 0; procedure = 1; record = 2; pointer = 3; end = 4; colon = 5;
lparen = 6; rparen = 7; semicolon = 8; eql = 9; arrow = 10; star = 11;
ident = 12; none = 99;
TYPE
Name = ARRAY 64 OF CHAR;
Class = POINTER TO ClassDesc;
Method = POINTER TO MethodDesc;
ClassDesc = RECORD
name: Name;
kind: INTEGER;
beg, end: LONGINT;
methods: Method;
link, next: Class
END;
MethodDesc = RECORD
beg, end: LONGINT;
next: Method
END;
ch: CHAR;
sym, lastSym: INTEGER;
pos, lastPos: LONGINT;
B: Texts.Buffer;
TMod, TOut: Texts.Text;
R: Texts.Reader;
W: Texts.Writer;
id: Name;
lineBeg: LONGINT;
lastID: Name;
lastIDline: LONGINT;
type: Name;
classes: Class;
(* scanner *)
PROCEDURE Ch;
BEGIN
Texts.Read(R, ch); INC(pos)
END Ch;
PROCEDURE Start(n: LONGINT);
BEGIN
pos := n; Texts.OpenReader(R, TMod, pos)
END Start;
PROCEDURE Comment;
BEGIN
LOOP
IF R.eot THEN RETURN
ELSIF ch = "*" THEN Ch; IF ch = ")" THEN Ch; RETURN END
ELSIF ch = "(" THEN Ch; IF ch = "*" THEN Ch; Comment END
ELSE Ch
END
END
END Comment;
PROCEDURE Ident;
VAR i: INTEGER;
BEGIN sym := ident; i := 0;
REPEAT id[i] := ch; Ch; INC(i) UNTIL (ch < "0") & (ch # ".") OR (ch > "9") & (CAP(ch) < "A") OR (CAP(ch) > "Z");
id[i] := 0X
END Ident;
PROCEDURE Sym;
VAR ch0: CHAR;
BEGIN
lastSym := sym; lastPos := pos; sym := none;
WHILE sym = none DO
CASE ch OF
| 0X: sym := eot
| 1X.." ": REPEAT IF ch = CR THEN lineBeg := pos END; Ch UNTIL (ch > " ") OR (ch = 0X)
| "a".."z", "A".."Z": Ident;
CASE id[0] OF
| "E": IF id = "END" THEN sym := end END
| "P": IF id = "PROCEDURE" THEN sym := procedure ELSIF id = "POINTER" THEN sym := pointer END
| "R": IF id = "RECORD" THEN sym := record END
ELSE
END;
IF sym = ident THEN lastID := id; lastIDline := lineBeg END
| "'", '"': ch0 := ch; REPEAT Ch UNTIL (ch = ch0) OR (ch < " ") OR R.eot; Ch
| "(": Ch; IF ch = "*" THEN Ch; Comment ELSE sym := lparen END
| ")": sym := rparen; Ch
| ":": sym := colon; Ch
| "=": sym := eql; Ch
| ";": sym := semicolon; Ch
| "^": sym := arrow; Ch
| "*": sym := star; Ch
ELSE Ch
END
END
END Sym;
(* parser *)
PROCEDURE FindClass(VAR id: Name; VAR c: Class);
BEGIN c := classes;
WHILE (c # NIL) & (c.name # id) DO c := c.next END
END FindClass;
PROCEDURE FindLink(VAR id: Name; VAR c: Class);
VAR p: Class;
BEGIN p := classes;
WHILE (p # NIL) & ((p.link = NIL) OR (p.link.name # id)) DO p := p.next END;
IF p = NIL THEN c := NIL ELSE c := p.link END
END FindLink;
PROCEDURE RecordType(VAR c: Class);
VAR ok: BOOLEAN; c0: Class;
BEGIN c := NIL;
ok := lastSym IN {eql, ident};
IF lastSym = eql THEN FindLink(lastID, c) END;
IF c = NIL THEN NEW(c); c.name := lastID; c.kind := record END;
c.beg := lastIDline;
LOOP Sym;
IF sym IN {end, eot} THEN c.end := lastPos - 1; EXIT
ELSIF sym = record THEN RecordType(c0) (*ignore nested records*)
END
END;
IF ~ok THEN c := NIL END
END RecordType;
PROCEDURE PointerType(VAR c: Class);
VAR ok: BOOLEAN; c0: Class;
BEGIN
ok := lastSym = eql;
NEW(c); c.name := lastID; c.kind := pointer; c.beg := lastIDline;
Sym; Sym;
IF sym = ident THEN
FindClass(id, c0);
IF c0 = NIL THEN NEW(c0); c0.name := id; c0.kind := record END;
c.link := c0; Sym; c.end := pos - 1;
ELSIF sym = record THEN
RecordType(c0); c.link := c0; c0.name := "";
c.end := lastPos - 1;
IF ok THEN c0.next := classes; classes := c0 END
ELSE ok := FALSE
END;
IF ~ok THEN c := NIL END
END PointerType;
PROCEDURE Procedure;
VAR m: Method; className: Name; c: Class;
BEGIN
NEW(m); m.beg := pos-10;
Sym; IF sym # lparen THEN RETURN END;
REPEAT Sym UNTIL sym IN {colon, eot};
Sym; className := id;
REPEAT Sym UNTIL sym IN {lparen, semicolon, eot};
IF sym = lparen THEN REPEAT Sym UNTIL sym IN {rparen, eot};
Sym; IF sym = colon THEN Sym; Sym END
END;
m.end := pos - 1;
FindClass(className, c); IF c = NIL THEN RETURN END;
IF c.kind = pointer THEN c := c.link END;
m.next := c.methods; c.methods := m
END Procedure;
(* output routines *)
PROCEDURE Wr(ch: CHAR);
BEGIN Texts.Write(W, ch); Texts.Append(TOut, W.buf)
END Wr;
PROCEDURE Str(s: ARRAY OF CHAR);
BEGIN Texts.WriteString(W, s); Texts.Append(TOut, W.buf)
END Str;
PROCEDURE Lead(pos: LONGINT): INTEGER;
VAR n: INTEGER;
BEGIN Start(pos); n := -1;
REPEAT Ch; INC(n) UNTIL (ch > " ") OR (ch = CR) OR R.eot;
RETURN n
END Lead;
PROCEDURE OutStretch(from, to: LONGINT; VAR ind, nLines: INTEGER; VAR leadCh: CHAR);
VAR lead, i: INTEGER; pos: LONGINT;
BEGIN
lead := Lead(from); nLines := 0;
REPEAT
ind := Lead(from) - lead; INC(nLines);
Start(from); FOR i := 1 TO lead DO Ch; INC(from) END;
IF ch = " " THEN leadCh := " " ELSE leadCh := TAB END;
pos := from;
WHILE (from < to) & (ch # CR) DO Ch; INC(from) END;
Texts.Save(TMod, pos, from, B); Texts.Append(TOut, B)
UNTIL from >= to;
END OutStretch;
PROCEDURE OutMethod(m: Method; ind: INTEGER; leadCh: CHAR);
VAR i, j: INTEGER; k: CHAR;
BEGIN
IF m # NIL THEN OutMethod(m.next, ind, leadCh);
FOR i := 1 TO ind DO Wr(leadCh) END;
OutStretch(m.beg, m.end, i, j, k); Wr(CR)
END;
END OutMethod;
PROCEDURE OutClass(c: Class);
VAR ind, nLines, i: INTEGER; leadCh: CHAR;
BEGIN
OutStretch(c.beg, c.end, ind, nLines, leadCh); Wr(CR);
IF nLines = 1 THEN INC(ind) END;
IF (c.kind = pointer) & (c.link # NIL) THEN
IF c.link.name = "" THEN c := c.link ELSIF type # "" THEN OutClass(c.link); RETURN END
END;
IF c.kind = record THEN
OutMethod(c.methods, ind, leadCh);
Str("END;"); Wr(CR)
END
END OutClass;
PROCEDURE OutAll(c: Class);
BEGIN
IF c # NIL THEN OutAll(c.next);
IF c.name # "" THEN OutClass(c) END
END
END OutAll;
(* main *)
PROCEDURE PrepName(s: ARRAY OF CHAR; VAR mod, type: ARRAY OF CHAR);
VAR i, j: INTEGER;
BEGIN i := 0;
REPEAT mod[i] := s[i]; INC(i) UNTIL (s[i-1] = 0X) OR (s[i-1] = ".");
IF s[i-1] = "." THEN mod[i] := "M"; mod[i+1] := "o"; mod[i+2] := "d"; mod[i+3] := 0X;
j := 0; REPEAT type[j] := s[i]; INC(i); INC(j) UNTIL s[i-1] = 0X
ELSE COPY(mod, type); mod[0] := 0X
END
END PrepName;
PROCEDURE Show*; (** ( "*" | "^" | name ) **)
VAR S: Texts.Scanner; V: Viewers.Viewer; text: Texts.Text; Menu, Text: TextFrames.Frame; x, y: INTEGER;
selbeg, selend, time: LONGINT; c: Class; m: Method; mod: Name;
BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
IF (S.class = Texts.Char) & (S.c = "*") & (S.line = 0) THEN V := Oberon.MarkedViewer();
IF (V # NIL) & (V.dsc # NIL) & (V.dsc.next # NIL) & (V.dsc.next IS TextFrames.Frame) THEN
TMod := V.dsc.next(TextFrames.Frame).text; type := ""
ELSE RETURN
END
ELSIF (S.class = Texts.Name) & (S.line = 0) THEN
PrepName(S.s, mod, type); TMod := TextFrames.Text(mod)
ELSE Oberon.GetSelection(text, selbeg, selend, time);
IF time > 0 THEN Texts.OpenScanner(S, text, selbeg); Texts.Scan(S);
IF (S.class # Texts.Name) OR (S.line > 0) THEN RETURN END
ELSE RETURN
END;
PrepName(S.s, mod, type);
IF mod = "" THEN TMod := text ELSE TMod := TextFrames.Text(mod) END
END;
Start(0); Ch; sym := none; lineBeg := 0; lastID := ""; lastIDline := 0; lastSym := none; classes := NIL;
LOOP Sym;
CASE sym OF
procedure: Procedure
| record: RecordType(c); IF c # NIL THEN c.next := classes; classes := c END
| pointer: PointerType(c); IF c # NIL THEN c.next := classes; classes := c END
| eot: EXIT
ELSE
END
END;
TOut := TextFrames.Text(""); NEW(B); Texts.OpenBuf(B);
Oberon.AllocateUserViewer(Oberon.Mouse.X, x, y);
V := MenuViewers.New(TextFrames.NewMenu(type, StdMenu), TextFrames.NewText(TOut, 0),
TextFrames.menuH, x, y);
IF type = "" THEN OutAll(classes)
ELSE FindClass(type, c); IF c # NIL THEN OutClass(c) END
END;
TMod := NIL; TOut := NIL; B := NIL; classes := NIL
END Show;
BEGIN Texts.OpenWriter(W)
END Class.